#include "external_con.h"
#include "inner_con.h"
#include "server.h"
#include <sys/time.h>

using namespace std;
using namespace proto;
using namespace lc;

ExternalSvrCon::ExternalSvrCon()
{
	if (0 != Server::Ins().m_cfg.GetMsbs())
	{
		SetMaxSendBufSize(Server::Ins().m_cfg.GetMsbs());
	}
}

ExternalSvrCon::~ExternalSvrCon()
{
	if (IsVerify())
	{
		const Id2Svr &id_2_svr = Server::Ins().m_regSvrMgr.GetRegSvr();
		for (auto &v: id_2_svr)
		{
			InnerSvrCon *p = v.second;
			L_COND_V(p);
			//LDEBUG("NtfDiscon", GetId());
			p->Call((char)AdCmd::NtfDiscon, GetId());
		}
		L_DEBUG("external verify client destroy . cid=%llx", GetId());
	}
}

void ExternalSvrCon::SetVerify(bool is_success) 
{
	L_COND_V(m_state == State::WAIT_VERIFY, "svr req CMD_REQ_VERIFY_RET state not correct");
	m_verify_tm.Stop();
	if (is_success)
	{
		m_state = State::VERIFYED;
		HeartBeatInfo& hbi = Server::Ins().m_seting.hbi;
		if (hbi.req_cmd != 0)
		{//reset heartbeat
			if (0 == hbi.interval_sec)
			{
				LERROR("0 == hbi.interval_sec");
				hbi.interval_sec = 10;
			}
			time(&m_lhtm);
			auto f = [this, span = hbi.interval_sec]()
			{
				time_t cur = 0;
				time(&cur);
				if (cur > m_lhtm + span)
				{
					LDEBUG("heartbeat time out, discon client");
					DisConnect();
				}
			};
			L_DEBUG("start heartbeat time sec=%d", hbi.interval_sec);
			m_heartbeat_tm.Start(hbi.interval_sec, f, true);
		}
	}
	else
	{
		m_state = State::WAIT_1ST_MSG;//认证失败
		DisConnect();
	}
}

bool ExternalSvrCon::IsVerify()const
{
	return State::VERIFYED == m_state;
}

bool ExternalSvrCon::SendMsg(uint32 cmd, const std::string& msg)
{
	string s;
	s.append((char *)&cmd, sizeof(cmd));
	s.append(msg.c_str(), msg.length());
	return SendPack(s.c_str(), s.length());
}

bool ExternalSvrCon::SetSession(uint16 svrType, uint16 svrId)
{
	L_COND_F(svrType < m_svrTypeIdxSvrId.size()); 
	
	if (0 != m_svrTypeIdxSvrId[svrType] && 0 != svrId)
	{
		LERROR("session have already set svrId", m_svrTypeIdxSvrId[svrType], ". can't replace by ", svrId);//会话不应该被替换。 同组svr之间， svr应该主动删除sn,然后再让其他svr创建sn
		return false;
	}

	m_svrTypeIdxSvrId[svrType] = svrId;
	return true;
}

void ExternalSvrCon::SetCache(bool isCache)
{
	if (!isCache)//恢复
	{
		lc::MsgPack msgPack;
		for (std::string &str : m_cacheMsg)
		{
			L_COND_V(str.length() < su::ArrayLen(msgPack.data));
			msgPack.len = str.length();
			memcpy(msgPack.data, str.c_str(), str.length());
			Forward2Svr(msgPack);
		}
		m_cacheMsg.clear();
	}
	m_isCache = isCache;
}

void ExternalSvrCon::DelSession(uint16 mainCmd, uint32 svrId)
{
	L_COND_V(mainCmd < m_svrTypeIdxSvrId.size());
	if (svrId == m_svrTypeIdxSvrId[mainCmd])
	{
		m_svrTypeIdxSvrId[mainCmd] = 0;
	}
}

bool ExternalSvrCon::IsConSvr(uint16 mainCmd, uint16 svrId) const
{
	L_COND_F(mainCmd < m_svrTypeIdxSvrId.size());
	return m_svrTypeIdxSvrId[mainCmd] == svrId;
}

void ExternalSvrCon::OnRecv(const lc::MsgPack &msg)
{	
	switch (m_state)
	{
	default:
		L_ERROR("unknow state %d", (int)m_state);
		break;
	case ExternalSvrCon::State::WAIT_DISCON:
		break;
	case ExternalSvrCon::State::WAIT_1ST_MSG:
		Forward2VerifySvr(msg);
		break;
	case ExternalSvrCon::State::WAIT_VERIFY:
		L_WARN("client repeated req verify, ignore");
		break;
	case ExternalSvrCon::State::VERIFYED:
		if (m_isCache)
		{
			L_DEBUG("cache msg");
			m_cacheMsg.emplace_back(msg.data, msg.len);
		}
		Forward2Svr(msg);
		break;
	}
	return;
}

void ExternalSvrCon::OnConnected()
{
	//L_DEBUG("ExternalSvrCon OnConnected . sec=%d", AccSeting::Ins().m_seting.no_msg_interval_sec);
	const ClientLimitInfo &cli = Server::Ins().m_seting.cli;
	if (Server::Ins().GetExConSize() > cli.max_num)
	{
		L_INFO("external con too much. cur size=%d. rsp_cmd=%d", Server::Ins().GetExConSize(), cli.rsp_cmd);
		SendMsg(cli.rsp_cmd, cli.rsp_msg);
		////延时断开，等上面消息发送出去。这个方法不可靠，可能发送失败。 以后再想办法。
		//auto f = std::bind(&ExternalSvrCon::DisConnect, this);
		//m_cls_tm.Start(1, f);
		m_state = State::WAIT_DISCON; //直接断开，需要测试下上面的消息能不能发出去
		DisConnect();
		return;
	}

	if (0 != Server::Ins().m_seting.noMsgSpanSec)
	{
		//L_DEBUG("start no msg timer . sec=%d", AccSeting::Ins().m_seting.no_msg_interval_sec);
		auto f=[this]()
		{
			L_INFO("wait client 1st msg time out, disconnect");
			DisConnect();
		};
		m_wfm_tm.Start(Server::Ins().m_seting.noMsgSpanSec, f);
	}
}

void ExternalSvrCon::Forward2VerifySvr(const lc::MsgPack& msg)
{
	L_COND_V(State::WAIT_1ST_MSG == m_state);

	m_wfm_tm.Stop();
	InnerSvrCon *pSvr = Server::Ins().m_verifySvrMgr.GetBLVerifySvr();
	if (nullptr == pSvr)
	{
		L_WARN("can't find verfify svr. maybe you havn't reg your verify svr.");
		DisConnect();
		return;
	}

	L_COND_V(msg.len >= sizeof(uint32));
	uint32 cmd = 0;
	const char* cur = msg.data;
	cmd = *(decltype(cmd)*)(cur);
	cur += sizeof(cmd);
	std::string str(cur, msg.len - sizeof(cmd));
	pSvr->Call((char)AdCmd::VerifyReq, GetId(), cmd, str); //内存复制了，讲究极限效率，可以继续写代码优化

	auto f = [this]()
	{
		L_ASSERT(State::WAIT_VERIFY == m_state);
		L_WARN("wait verify time out, disconnect client");//通常验证服务器异常，导致没验证响应。当连接失败处理
		DisConnect();
	};
	m_verify_tm.Stop();
	m_verify_tm.Start(VERIFY_TIME_OUT_SEC, f);
	m_state = State::WAIT_VERIFY;
}

void ExternalSvrCon::Forward2Svr(const lc::MsgPack& msg)
{
	L_COND_V(msg.len >= sizeof(uint32));
	uint32 cmd = 0;
	const char* cur = msg.data;
	cmd = *(decltype(cmd)*)(cur);
	cur += sizeof(cmd);
	std::string str(cur, msg.len - sizeof(cmd));

	const HeartBeatInfo &hbi = Server::Ins().m_seting.hbi;
	if (hbi.req_cmd == cmd)
	{//reset heartbeat
		time(&m_lhtm);
		SendMsg(hbi.rsp_cmd, "");
		return;
	}
	uint8 mainCmd = cmd >> 16;
	L_COND_V((size_t)mainCmd < m_svrTypeIdxSvrId.size());
	uint16 svrId = m_svrTypeIdxSvrId[mainCmd];
	if (0 == svrId)
	{
		LWARN("can't find session to forward. mainCmd=", mainCmd);
		return;
	}

	//L_DEBUG("cmd=%x HeartbeatInfo::Ins().cmd=%x %x", cmd, AccSeting::Ins().m_seting.hbi.req_cmd, AccSeting::Ins().m_seting.hbi.rsp_cmd);
	InnerSvrCon *pSvr = Server::Ins().m_regSvrMgr.Find(svrId);
	if (nullptr == pSvr)
	{
		L_WARN("client req can't find svr. cmd=%x svrId=%d main_cmd=%d", cmd, svrId, cmd);
		return;
	}
	if (!pSvr->IsReg())
	{
		L_WARN("client req find svr, but not reg ok. cmd=%x svrId=%d main_cmd=%d", cmd, svrId, cmd);
		return;
	}

	pSvr->Call((char)AdCmd::Forward, GetId(), cmd, str);
}



